#pragma once

#include <iostream>
#include <string>
#include <sstream>
#include "comm.hpp"
#include "Socket.hpp"
#include <jsoncpp/json/json.h>

using namespace SocketModule;
// 定制协议
class Request
{
public:
    // 有参构造，客户端用于发送数据
    Request(int x, int y, char op)
        : _x_1(x),
          _y_2(y),
          _oper(op)
    {}

    // 无参构造，服务端用于接收数据
    Request() {}
    ~Request() {}

    std::string Serialize()
    {
        // 序列化
        Json::Value root;
        root["_x_1"] = _x_1;
        root["_y_2"] = _y_2;
        root["_oper"] = _oper;

        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> writer (swb.newStreamWriter());
        std::stringstream ss;
        writer->write(root, &ss);
        return ss.str();
    }
    bool Deserialize(std::string &json_str)
    {
        // 反序列化
        Json::Value root;
        Json::Reader reader;

        // 解析成功
        if(reader.parse(json_str, root)){
            _x_1 = root["_x_1"].asInt();
            _y_2 = root["_y_2"].asInt();
            _oper = root["_oper"].asInt();
            return true;
        }
        return false;
    }

    int X() { return _x_1; }
    int Y() { return _y_2 ;}
    char Oper() { return _oper; }

private:
    int _x_1;
    int _y_2;
    char _oper;
};

class Response
{
public:
    // 有参构造，服务端用于发送结果
    Response(int result, int code)
        : _result(result),
          _code(code)
    {}
    // 无参构造，客户端用户接收结果
    Response() {}
    ~Response() {}

    std::string Serialize()
    {
        // 序列化
        Json::Value root;
        root["_result"] = _result;
        root["_code"] = _code;

        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> writer(swb.newStreamWriter());
        std::stringstream ss;
        writer->write(root, &ss);
        return ss.str();
    }
    bool Deserialize(std::string &json_str)
    {
        // 反序列化
        Json::Value root;
        Json::Reader reader;
        
        if(reader.parse(json_str, root)){
            _result = root["_result"].asInt();
            _code = root["_code"].asInt();
            return true;
        }
        return false;
    }

    void Result(int res) { _result = res; }
    void Code(int code) { _code = code; }

    void ShowResult() { std::cout << "result->" << _result << "#[" << _code << "]" << std::endl; }
private:
    int _result; // 计算结果
    int _code;   // 结果是否正确
};


// 但是仅仅有序列化和反序列化不能够保证，服务器每次读上来的请求就是一个或者多个完整的报文
// 因为tcp是面向字节流的
// 所以，我们要在序列化之后的json string的头部添加长度报头，表明该json string的长度
// 当服务器读时，先判断是否读到了前面的长度报头，再根据长度报头，以及整个json string的长度，来判断读取的报文是否完整

/*
{
        "oper" : 43,
        "x" : 100,
        "y" : 200
}
*/

const std::string sep = "\r\n";
using deal_t = std::function<Response(Request &ret)>;
class protocol
{
public:
    protocol() {}
    protocol(deal_t deal) : _deal(deal) {}
    // 添加完长度报头之后
    /*
    len
    {
            "oper" : 43,
            "x" : 100,
            "y" : 200
    }
    */
    std::string Encode(const std::string &json_ptr)
    {
        // 添加长度报头 -> 封装
        int len = json_ptr.size();
        return std::to_string(len) + sep + json_ptr + sep;
    }

    // 从接收缓冲区读上来的串可能并不完整，有多种可能
    /*
    le
    len
    len
    {
            "oper"
    }
    len
    {
            "oper" : 43;
    }
    len
    {
            "oper" : 43,
            "x" : 100,
            "y" : 200
    }
    */// package_ptr:有报头的，json_ptr:输出型参数，用于拿出解包后的json串
    // 问题：上面的json串格式，是否可以使用\r\n来作为分割符????????????????????????????
    bool Decode(std::string &package_ptr, std::string *json_ptr) 
    {
        // 删除长度报头 -> 解包
        // 1. 判断是否读到了长度报头
        size_t pos = package_ptr.find(sep);
        if(pos == std::string::npos) return false;

        // 2.至少读到了长度报头,接下来判断是否为一个完整的json串
        std::string target_len = package_ptr.substr(0, pos); // 字符串的内容是一个完整报文的长度
        int sum_len = std::stoi(target_len) + 2 * sep.size()/*分割符长度*/ + target_len.size()/*报头长度*/;
        if(sum_len > package_ptr.size()) return false;

        // 3.至少有一个完整的报文
        *json_ptr = package_ptr.substr(pos + sep.size(), std::stoi(target_len));
        package_ptr.erase(0, sum_len);
        return true;
    }
    void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string buffer;
        while(true){
            // 1. 获取报文
            std::string json_ptr;
            ssize_t n = sock->Recv(&buffer); // n就是读取的字符串的长度
            if(n > 0){
                //std::cout << "-------------buffer--------------------" << std::endl;
                //std::cout << buffer << std::endl;
                //std::cout << "-----------------------------------------" << std::endl;
                //if(!Decode(buffer, &json_ptr)) continue;

                while(Decode(buffer, &json_ptr)){
                    //std::cout << "-------------json_ptr--------------------" << std::endl;
                    //std::cout << json_ptr << std::endl;
                    //std::cout << "-----------------------------------------" << std::endl;

                    //std::cout << "-------------buffer--------------------" << std::endl;
                    //std::cout << buffer << std::endl;
                    //std::cout << "-----------------------------------------" << std::endl;
                
                    LOG(loglevel::DEBUG) << client.InetToString() << "请求->" << json_ptr;
                    // 这里就是一个完整的报文
                    // 2.反序列化报文
                    Request req;
                    if(!req.Deserialize(json_ptr)) continue;

                    // 3.处理
                    Response resp = _deal(req);

                    // 4.对结果进行序列化
                    std::string json_resp = resp.Serialize();

                    // 5.添加报头
                    std::string package_resp = Encode(json_resp);

                    // 6.发送
                    sock->Send(package_resp);
                }
            }
            else if(n == 0){
                LOG(loglevel::INFO) << "client :" << client.InetToString() << "quit";
                break;
            }
            else{
                LOG(loglevel::WARINING) << "client :" << client.InetToString() << "read error";
                break;
            }
        }
    }

    std::string BuildRequest(Request &req)
    {
        // 1.序列化
        std::string req_json = req.Serialize();
        // 2.添加长度报头
        return Encode(req_json);
    }

    bool GetResponse(std::shared_ptr<Socket> &sock, std::string &resp_buffer, Response *resp)
    {
        // 读取时是面向字节流的，读取时需要保证读取到一个完整的响应字符串
        while(true){
            ssize_t n = sock->Recv(&resp_buffer);
            //std::cout << "----------------resp_buffer----------------------" << std::endl;
            //std::cout << resp_buffer << std::endl;
            //std::cout << "-------------------------------------------------" << std::endl;
            if(n > 0){
                std::string resp_json;
                //if(!Decode(resp_buffer, &resp_json)) continue;
                while(Decode(resp_buffer, &resp_json)){
                    //std::cout << "----------------resp_json----------------------" << std::endl;
                    //std::cout << resp_json << std::endl;
                    //std::cout << "-------------------------------------------------" << std::endl;

                    //std::cout << "----------------resp_buffer----------------------" << std::endl;
                    //std::cout << resp_buffer << std::endl;
                    //std::cout << "-------------------------------------------------" << std::endl;

                    // 往下，就有了一个完整的响应字符串
                    // 反序列化
                    if(!resp->Deserialize(resp_json)) continue;

                    //resp->ShowResult();
                }
                return true; 
            }
            else if(n == 0){
                std::cerr << "server quit" << std::endl;
                return false;
            }
            else{
                std::cerr << "read error" << std::endl;
                return false;
            }
        }
    }
private:
    deal_t _deal;
};